use std::{error, sync::Arc};

use axum::{
    Json,
    response::{IntoResponse, Response},
};
use sea_orm::DatabaseConnection;
use serde::Serialize;

use crate::{config::AppConfig, dto::status_code};

/// 通用返回值，使用它主要用来可以结合？语法来返回
pub type RetVal<T = ()> = core::result::Result<ApiResult<T>, ApiResult>;

// 全局上下文数据
#[derive(Clone, Debug)]
pub struct AppContext {
    pub db: DatabaseConnection,
    pub env: Arc<AppConfig>,
}

/// 通用返回值结构
#[derive(Serialize)]
#[serde(untagged)] // 注意这里关闭了类型标记，这对反序列化来说有一定的性能影响，但我们的场景只是序列化 就不需要考虑了。
pub enum ApiResult<T = ()> {
    // 基本返回值
    Ok { code: u16, msg: String },
    // 带数据的返回值
    Data { code: u16, msg: String, data: T },
}

impl<T: Serialize> IntoResponse for ApiResult<T> {
    fn into_response(self) -> Response {
        Json(self).into_response()
    }
}

/// 返回值辅助类
pub struct RetValHelper;

impl RetValHelper {
    pub fn ok() -> RetVal {
        Ok(Self::inner_with_status(status_code::OK))
    }

    pub fn error<T>() -> RetVal<T> {
        Err(Self::inner_error())
    }

    pub fn inner_error<T>() -> ApiResult<T> {
        Self::inner_with_status(status_code::INTERNAL_ERROR)
    }

    pub fn with_status<T>(cm: (u16, impl ToString)) -> RetVal<T> {
        Ok(Self::inner_with_status(cm))
    }

    pub fn inner_with_status<T>(cm: (u16, impl ToString)) -> ApiResult<T> {
        ApiResult::Ok {
            code: cm.0,
            msg: cm.1.to_string(),
        }
    }

    pub fn with_data<T: Serialize>(data: T) -> RetVal<T> {
        Ok(ApiResult::Data {
            code: status_code::OK.0,
            msg: status_code::OK.1.to_string(),
            data,
        })
    }
}

/// 方便问号操作符使用
impl<T: error::Error> From<T> for ApiResult {
    fn from(value: T) -> Self {
        log::error!("{:?}", value);
        ApiResult::Ok {
            code: status_code::INTERNAL_ERROR.0,
            msg: status_code::INTERNAL_ERROR.1.to_string(),
        }
    }
}
